package utils;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * @author Xinjie
 * @date 2023/9/25 11:26
 */
public class TopicUtils {
    static Random random = new Random();

    /**
     * 生成题目并计算答案
     *
     * @param num   题目数量
     * @param range 题目数值范围
     * @return 题目
     */
    public static Map<String, String[]> generateTopic(int num, int range) {
        Map<String, String[]> map = new HashMap<>();
        String[] expressions = new String[num];
        for (int i = 0; i < num; i++) {
            //运算符个数
            int operatorNum = random.nextInt(2) + 1;
            System.out.println("operatorNum:" + operatorNum);
            //记录运算符
            int[] operators = new int[operatorNum];
            for (int j = 0; j < operatorNum; j++) {
                //随机生成运算符
                int operator = random.nextInt(3);
                operators[j] = operator;
            }
            String[] operands = new String[operatorNum + 1];
            //运算数生成
            for (int k = 0; k <= operatorNum; k++) {
                String operand = generateNum(range);
                operands[k] = operand;
            }
            //表达式生成
            StringBuilder expression = new StringBuilder();
            for (int j = 0; j < operatorNum; j++) {
                expression.append(operands[j]);
                if (operators[j] == 0) {
                    expression.append("+");
                } else if (operators[j] == 1) {
                    //减号可能会出现负数，就修改为整数
                    while (operands[j].compareTo(operands[j + 1]) < 0) {
                        operands[j + 1] = generateNum(range);
                    }
                    expression.append("-");
                } else if (operators[j] == 2) {
                    expression.append("*");
                } else {
                    expression.append("÷");
                }
            }
            expression.append(operands[operatorNum]);
            expressions[i] = expression.toString();
        }
        map.put("topics", expressions);
        String[] compute = compute(expressions);
        map.put("answers", compute);
        return map;
    }

    private static String generateNum(int range) {
        //判断是否生成分数
        boolean b = random.nextBoolean();
        //生成分数
        if (b) {
            //分子
            int numerator = random.nextInt(range);
            //分母
            int denominator = random.nextInt(range - 1) + 1;
            //拼接
            return reductionOfFraction(numerator, denominator);
        } else {//生成自然数
            int operand = random.nextInt(range);
            return String.valueOf(operand);
        }
    }

    /**
     * 计算答案
     *
     * @param expressions 题目
     * @return 答案
     */
    private static String[] compute(String[] expressions) {
        String[] answers = new String[expressions.length];
        int k = 0;
        for (String expression : expressions) {
            int j = 0;
            int[] operators = new int[4];
            for (int i = 0; i < expression.length(); i++) {
                char c = expression.charAt(i);
                if (c == '+' || c == '-' || c == '*' || c == '÷') {
                    //记录符号位置
                    operators[j++] = i;
                }
            }
            String result = "0";
            boolean flag = true;
            for (int i = 0; i < operators.length; i++) {
                System.out.println("k:" + k + "operators:" + operators[i]);
                if (operators[i] != 0 || flag) {
                    //第一个运算符
                    if (i == 0) {
                        result = expression.substring(0, operators[i]);
                    } else {
                        char c = expression.charAt(operators[i - 1]);
                        String substring;
                        if (operators[i] == 0) {
                            substring = expression.substring(operators[i - 1] + 1);
                        } else {
                            substring = expression.substring(operators[i - 1] + 1, operators[i]);
                        }
                        if (c == '+') {
                            result = addCompute(result, substring);
                        } else if (c == '-') {
                            result = cutCompute(result, substring);
                        } else if (c == '*') {
                            result = multiCompute(result, substring);
                        } else if (c == '÷') {
                            result = divisCompute(result, substring);
                        }
                    }
                    if (operators[i] == 0) {
                        flag = false;
                    }
                }
            }
            answers[k++] = result;
        }
        return answers;
    }

    private static String divisCompute(String result, String substring) {
        System.out.println("sub:" + substring);
        System.out.println("result:" + result);
        String mark1;
        //第二个运算数为带分数
        if (substring.contains(" ")) {
            //获取带分数前的整数
            int index = substring.indexOf(" ");
            System.out.println("index:" + index);
            String substring1 = substring.substring(0, index);
            //获取带分数的分数部分
            String substring2 = substring.substring(index + 1);
            //获取分子分母
            String[] split = substring2.split("/");
            int i3 = Integer.parseInt(split[1]) * Integer.parseInt(substring1) + Integer.parseInt(split[0]);
            mark1 = i3 + "/" + split[1];
        } else {//其他情况
            mark1 = substring;
        }
        String mark2;
        if (result.contains(" ")) {
            //获取带分数前的整数
            int index = result.indexOf(" ");
            System.out.println("index:" + index);
            String substring1 = result.substring(0, index);
            //获取带分数的分数部分
            String substring2 = result.substring(index + 1);
            //获取分子分母
            String[] split = substring2.split("/");
            int i3 = Integer.parseInt(split[1]) * Integer.parseInt(substring1) + Integer.parseInt(split[0]);
            mark2 = i3 + "/" + split[1];
        } else {
            mark2 = result;
        }
        int i1 = mark1.indexOf("/");
        int i2 = mark2.indexOf("/");
        System.out.println("mark1:" + mark1);
        System.out.println("mark2:" + mark2);
        //都为整数
        if (i1 < 0 && i2 < 0) {
            result = reductionOfFraction(Integer.parseInt(mark2), Integer.parseInt(mark1));
        } else if (i1 >= 0 && i2 < 0) {//一个分数
            String[] split = mark1.split("/");
            result = reductionOfFraction(Integer.parseInt(mark2) * Integer.parseInt(split[1]), Integer.parseInt(split[0]));
        } else if (i1 < 0) {//一个分数
            String[] split = mark2.split("/");
            result = reductionOfFraction(Integer.parseInt(split[0]), Integer.parseInt(split[1]) * Integer.parseInt(mark1));
        } else {//都为分数
            String[] split1 = mark1.split("/");
            String[] split2 = mark2.split("/");
            result = reductionOfFraction(Integer.parseInt(split1[1]) * Integer.parseInt(split2[0]), Integer.parseInt(split1[0]) * Integer.parseInt(split2[1]));
        }
        return result;
    }

    /**
     * 乘法
     *
     * @param result    前一步结果
     * @param substring 运算数
     * @return 结果
     */
    private static String multiCompute(String result, String substring) {
        System.out.println("sub:" + substring);
        System.out.println("result:" + result);
        String mark1;
        //第二个运算数为带分数
        if (substring.contains(" ")) {
            //获取带分数前的整数
            int index = substring.indexOf(" ");
            System.out.println("index:" + index);
            String substring1 = substring.substring(0, index);
            //获取带分数的分数部分
            String substring2 = substring.substring(index + 1);
            //获取分子分母
            String[] split = substring2.split("/");
            int i3 = Integer.parseInt(split[1]) * Integer.parseInt(substring1) + Integer.parseInt(split[0]);
            mark1 = i3 + "/" + split[1];
        } else {//不为带分数
            mark1 = substring;
        }
        String mark2;
        if (result.contains(" ")) {
            //获取带分数前的整数
            int index = result.indexOf(" ");
            System.out.println("index:" + index);
            String substring1 = result.substring(0, index);
            //获取带分数的分数部分
            String substring2 = result.substring(index + 1);
            //获取分子分母
            String[] split = substring2.split("/");
            int i3 = Integer.parseInt(split[1]) * Integer.parseInt(substring1) + Integer.parseInt(split[0]);
            mark2 = i3 + "/" + split[1];
        } else {
            mark2 = result;
        }
        System.out.println("mark1:" + mark1);
        System.out.println("mark2:" + mark2);
        int i1 = mark1.indexOf("/");
        int i2 = mark2.indexOf("/");
        //都为整数
        if (i1 < 0 && i2 < 0) {
            result = Integer.parseInt(mark1) * Integer.parseInt(mark2) + "";
        } else if (i1 >= 0 && i2 < 0) {//一个分数
            String[] split = mark1.split("/");
            result = reductionOfFraction(Integer.parseInt(mark2) * Integer.parseInt(split[0]), Integer.parseInt(split[1]));
        } else if (i1 < 0) {//一个分数
            String[] split = mark2.split("/");
            result = reductionOfFraction(Integer.parseInt(split[0]) * Integer.parseInt(mark1), Integer.parseInt(split[1]));
        } else {//都为分数
            String[] split1 = mark1.split("/");
            String[] split2 = mark2.split("/");
            result = reductionOfFraction(Integer.parseInt(split1[0]) * Integer.parseInt(split2[0]), Integer.parseInt(split1[1]) * Integer.parseInt(split2[1]));
        }
        return result;
    }

    /**
     * 减法
     *
     * @param result    前一步结果
     * @param substring 运算数
     * @return 结果
     */
    private static String cutCompute(String result, String substring) {
        System.out.println("sub:" + substring);
        System.out.println("result:" + result);
        String mark1;
        //第二个运算数为带分数
        if (substring.contains(" ")) {
            //获取带分数前的整数
            int index = substring.indexOf(" ");
            System.out.println("index:" + index);
            String substring1 = substring.substring(0, index);
            //获取带分数的分数部分
            String substring2 = substring.substring(index + 1);
            //获取分子分母
            String[] split = substring2.split("/");
            int i3 = Integer.parseInt(split[1]) * Integer.parseInt(substring1) + Integer.parseInt(split[0]);
            mark1 = i3 + "/" + split[1];
        } else {//不为带分数
            mark1 = substring;
        }
        String mark2;
        if (result.contains(" ")) {
            //获取带分数前的整数
            int index = result.indexOf(" ");
            System.out.println("index:" + index);
            String substring1 = result.substring(0, index);
            //获取带分数的分数部分
            String substring2 = result.substring(index + 1);
            //获取分子分母
            String[] split = substring2.split("/");
            int i3 = Integer.parseInt(split[1]) * Integer.parseInt(substring1) + Integer.parseInt(split[0]);
            mark2 = i3 + "/" + split[1];
        } else {
            mark2 = result;
        }
        int i1 = mark1.indexOf("/");
        int i2 = mark2.indexOf("/");
        System.out.println("mark1:" + mark1);
        System.out.println("mark2:" + mark2);
        //都为整数
        if (i1 < 0 && i2 < 0) {
            int i = Integer.parseInt(mark2) - Integer.parseInt(mark1);
            result = i + "";
        } else if (i1 >= 0 && i2 < 0) {//一个分数
            String[] split = mark1.split("/");
            result = reductionOfFraction(Integer.parseInt(mark2) * Integer.parseInt(split[1]) - Integer.parseInt(split[0]), Integer.parseInt(split[1]));
        } else if (i1 < 0) {//一个分数
            String[] split = mark2.split("/");
            result = reductionOfFraction(Integer.parseInt(split[0]) - Integer.parseInt(split[1]) * Integer.parseInt(mark1), Integer.parseInt(split[1]));
        } else {//都为分数
            String[] split1 = mark1.split("/");
            String[] split2 = mark2.split("/");
            result = reductionOfFraction(Integer.parseInt(split2[0]) * Integer.parseInt(split1[1]) - Integer.parseInt(split1[0]) * Integer.parseInt(split2[1]), Integer.parseInt(split1[1]) * Integer.parseInt(split2[1]));
        }
        return result;
    }

    private static String addCompute(String result, String substring) {
        System.out.println("sub:" + substring);
        System.out.println("result:" + result);
        String mark1;
        //第二个运算数为带分数
        if (substring.contains(" ")) {
            //获取带分数前的整数
            int index = substring.indexOf(" ");
            System.out.println("index:" + index);
            String substring1 = substring.substring(0, index);
            //获取带分数的分数部分
            String substring2 = substring.substring(index + 1);
            //获取分子分母
            String[] split = substring2.split("/");
            int i3 = Integer.parseInt(split[1]) * Integer.parseInt(substring1) + Integer.parseInt(split[0]);
            mark1 = i3 + "/" + split[1];
        } else {//不为带分数
            mark1 = substring;
        }
        String mark2;
        if (result.contains(" ")) {
            //获取带分数前的整数
            int index = result.indexOf(" ");
            System.out.println("index:" + index);
            String substring1 = result.substring(0, index);
            //获取带分数的分数部分
            String substring2 = result.substring(index + 1);
            //获取分子分母
            String[] split = substring2.split("/");
            int i3 = Integer.parseInt(split[1]) * Integer.parseInt(substring1) + Integer.parseInt(split[0]);
            mark2 = i3 + "/" + split[1];
        } else {
            mark2 = result;
        }
        int i1 = mark1.indexOf("/");
        int i2 = mark2.indexOf("/");
        System.out.println("mark1:" + mark1);
        System.out.println("mark2:" + mark2);
        //都为整数
        if (i1 < 0 && i2 < 0) {
            int i = Integer.parseInt(mark1) + Integer.parseInt(mark2);
            result = i + "";
        } else if (i1 >= 0 && i2 < 0) {//一个分数
            String[] split = mark1.split("/");
            result = reductionOfFraction(Integer.parseInt(mark2) * Integer.parseInt(split[1]) + Integer.parseInt(split[0]), Integer.parseInt(split[1]));
        } else if (i1 < 0) {//一个分数
            String[] split = mark2.split("/");
            result = reductionOfFraction(Integer.parseInt(split[1]) * Integer.parseInt(mark1) + Integer.parseInt(split[0]), Integer.parseInt(split[1]));
        } else {//都为分数
            String[] split1 = mark1.split("/");
            String[] split2 = mark2.split("/");
            result = reductionOfFraction(Integer.parseInt(split1[0]) * Integer.parseInt(split2[1]) + Integer.parseInt(split2[0]) * Integer.parseInt(split1[1]), Integer.parseInt(split1[1]) * Integer.parseInt(split2[1]));
        }
        return result;
    }

    /**
     * 约分
     *
     * @param numerator   分子
     * @param denominator 分母
     * @return
     */
    private static String reductionOfFraction(int numerator, int denominator) {
        System.out.println("numerator:" + numerator);
        System.out.println("denominator" + denominator);
        int y = 1;
        for (int i = numerator; i >= 1; i--) {
            if (numerator % i == 0 && denominator % i == 0) {
                y = i;
                break;
            }
        }
        // 分子
        int z = numerator / y;
        // 分母
        int m = denominator / y;
        System.out.println("z:" + z);
        System.out.println("m:" + m);
        if (z == 0) {
            return "0";
        }
        if (m == 1) {
            return z + "";
        } else {
            return convertToValid(z, m);
        }
    }

    /**
     * 假分数转为带分数
     *
     * @param numerator   分子
     * @param denominator 分母
     * @return
     */
    private static String convertToValid(int numerator, int denominator) {
        if (numerator >= denominator) {
            int i = numerator / denominator;
            int j = numerator % denominator;
            if (j == 0) {
                return i + "";
            } else {
                return i + " " + j + "/" + denominator;
            }
        } else {
            return numerator + "/" + denominator;
        }
    }
}
